//////////////////////////////////////////ok
#include"stdafx.h"
#include "bochs.h"



void  IA32_CPU::ARPL_EwGw(Ia32_Instruction_c *i)
{

	Bit16u op2_16, op1_16;

	if (i->modC0()) 
	{
		op1_16 = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
	}

	op2_16 = IA32_READ_16BIT_REG(i->nnn());

	if ((op1_16 & 0x03) < (op2_16 & 0x03)) 
	{
		op1_16 = (op1_16 & 0xfffc) | (op2_16 & 0x03);
		if (i->modC0()) 
		{
			if (i->os32L()) 
			{
				Bit32u op1_32 = IA32_READ_32BIT_REG(i->rm());
				op1_32 = (op1_32 & 0xffff0000) | op1_16;
				op1_32 |= 0xff3f0000;
				IA32_WRITE_32BIT_REGZ(i->rm(), op1_32);
			}
			else 
			{
				IA32_WRITE_16BIT_REG(i->rm(), op1_16);
			}
		}
		else 
		{
			write_RMW_virtual_word(op1_16);
		}
		set_ZF(1);
	}
	else 
	{
		set_ZF(0);
	}

}

void  IA32_CPU::LAR_GvEw(Ia32_Instruction_c *i)
{
	Bit16u raw_selector;
	ia32_descriptor_t descriptor;
	ia32_selector_t selector;
	Bit32u dword1, dword2;

	if (i->modC0()) 
	{
		raw_selector = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &raw_selector);
	}

	if ((raw_selector & 0xfffc) == 0) 
	{
		set_ZF(0);
		return;
	}

	parse_selector(raw_selector, &selector);
	if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) 
	{
		set_ZF(0);
		return;
	}

	parse_descriptor(dword1, dword2, &descriptor);
	if (descriptor.valid==0) 
	{
		set_ZF(0);
		return;
	}

	if (descriptor.segment) 
	{ /* normal segment */
		if (descriptor.u.segment.executable && descriptor.u.segment.c_ed) 
		{
			/* ignore DPL for conforming segments */
		}
		else 
		{
			if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) 
			{
				set_ZF(0);
				return;
			}
		}
		set_ZF(1);
		if (i->os32L()) 
		{
			IA32_WRITE_32BIT_REGZ(i->nnn(), dword2 & 0x00ffff00);
		}
		else 
		{
			IA32_WRITE_16BIT_REG(i->nnn(), dword2 & 0xff00);
		}
		return;
	}
	else 
	{ /* system or gate segment */
		switch (descriptor.type) 
		{
		case IA32_SYS_SEGMENT_AVAIL_286_TSS:
		case IA32_SYS_SEGMENT_LDT:
		case IA32_SYS_SEGMENT_BUSY_286_TSS:
		case IA32_286_CALL_GATE:
		case IA32_TASK_GATE:
		case IA32_SYS_SEGMENT_AVAIL_386_TSS:
		case IA32_SYS_SEGMENT_BUSY_386_TSS:
		case IA32_386_CALL_GATE:
			break;
		default: /* rest not accepted types to LAR */
			set_ZF(0);
			return;
		}

		if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) 
		{
			set_ZF(0);
			return;
		}
		set_ZF(1);
		if (i->os32L()) 
		{
			IA32_WRITE_32BIT_REGZ(i->nnn(), dword2 & 0x00ffff00);
		}
		else 
		{
			IA32_WRITE_16BIT_REG(i->nnn(), dword2 & 0xff00);
		}
	}
}

void  IA32_CPU::LSL_GvEw(Ia32_Instruction_c *i)
{
	Bit16u raw_selector;
	Bit32u limit32;
	ia32_selector_t selector;
	Bit32u dword1, dword2;
	Bit32u descriptor_dpl;

	if (i->modC0()) 
	{
		raw_selector = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &raw_selector);
	}

	if ((raw_selector & 0xfffc) == 0) 
	{
		set_ZF(0);
		return;
	}

	parse_selector(raw_selector, &selector);
	if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) 
	{
		set_ZF(0);
		return;
	}

	descriptor_dpl = (dword2 >> 13) & 0x03;
	if ((dword2 & 0x00001000) == 0) 
	{ // system segment
		Bit32u type = (dword2 >> 8) & 0x0000000f;
		switch (type) 
		{
		case IA32_SYS_SEGMENT_AVAIL_286_TSS:
		case IA32_SYS_SEGMENT_BUSY_286_TSS:
		case IA32_SYS_SEGMENT_LDT:
		case IA32_SYS_SEGMENT_AVAIL_386_TSS:
		case IA32_SYS_SEGMENT_BUSY_386_TSS:
			limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
			if (dword2 & 0x00800000)
				limit32 = (limit32 << 12) | 0x00000fff;
			if ((descriptor_dpl<CPL) || (descriptor_dpl<selector.rpl)) 
			{
				set_ZF(0);
				return;
			}
			goto lsl_ok;
			break;
		default:
			set_ZF(0);
			return;
		}
	}
	else 
	{ // data & code segment
		limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);

		if (dword2 & 0x00800000)
			limit32 = (limit32 << 12) | 0x00000fff;

		if ((dword2 & 0x00000c00) == 0x00000c00) 
		{
			goto lsl_ok;
		}

		if ((descriptor_dpl<CPL) || (descriptor_dpl<selector.rpl)) 
		{
			set_ZF(0);
			return;
		}
		goto lsl_ok;
	}

lsl_ok:
	set_ZF(1);

	if (i->os32L())
		IA32_WRITE_32BIT_REGZ(i->nnn(), limit32)
	else
	IA32_WRITE_16BIT_REG(i->nnn(), (Bit16u) limit32)
}

void  IA32_CPU::SLDT_Ew(Ia32_Instruction_c *i)
{
	Bit16u val16 =  ldtr.selector.value;
	if (i->modC0()) 
	{
		IA32_WRITE_16BIT_REG(i->rm(), val16);
	}
	else 
	{
		write_virtual_word(i->seg(), IA32_RMAddr(i), &val16);
	}

}

void  IA32_CPU::STR_Ew(Ia32_Instruction_c *i)
{
	Bit16u val16 =  tr.selector.value;
	if (i->modC0()) 
	{
		IA32_WRITE_16BIT_REG(i->rm(), val16);
	}
	else 
	{
		write_virtual_word(i->seg(), IA32_RMAddr(i), &val16);
	}
}

void  IA32_CPU::LLDT_Ew(Ia32_Instruction_c *i)
{

	invalidate_prefetch_q();
	ia32_descriptor_t  descriptor;
	ia32_selector_t    selector;
	Bit16u raw_selector;
	Bit32u dword1, dword2;

	if (CPL != 0) 
	{
		exception(IA32_GP_EXCEPTION, 0, 0);
	}

	if (i->modC0()) 
	{
		raw_selector = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &raw_selector);
	}

	if ((raw_selector & 0xfffc) == 0) 
	{
		ldtr.selector.value = raw_selector;
		ldtr.cache.valid = 0;
		return;
	}

	parse_selector(raw_selector, &selector);
	if (selector.ti != 0) 
	{
		exception(IA32_GP_EXCEPTION, raw_selector & 0xfffc, 0);
	}

	if ((selector.index*8 + 7) >  gdtr.limit) 
	{
		exception(IA32_GP_EXCEPTION, raw_selector & 0xfffc, 0);
		return;
	}

	m_vm32->access_address_n(this, gdtr.base + selector.index*8,     4, 0, IA32_READ, &dword1);
	m_vm32->access_address_n(this, gdtr.base + selector.index*8 + 4, 4, 0, IA32_READ, &dword2);
#ifdef IA32_BIG_ENDIAN
	IA32_ReadHostDWordFromLittleEndian(&dword1, &dword1);
	IA32_ReadHostDWordFromLittleEndian(&dword2, &dword2);
#endif
	parse_descriptor(dword1, dword2, &descriptor);
	if (descriptor.valid == 0 || descriptor.segment || descriptor.type != IA32_SYS_SEGMENT_LDT) 
	{
		exception(IA32_GP_EXCEPTION, raw_selector & 0xfffc, 0);
	}

	if (descriptor.p==0) 
	{
		exception(IA32_NP_EXCEPTION, raw_selector & 0xfffc, 0);
	}

	if (descriptor.u.ldt.limit < 7) 
	{
		// BX_ERROR(("LLDT: ldtr.limit < 7"));
	}

	ldtr.selector = selector;
	ldtr.cache = descriptor;
	ldtr.cache.valid = 1;
}

void IA32_CPU::LTR_Ew(Ia32_Instruction_c *i)
{

	invalidate_prefetch_q();
	ia32_descriptor_t descriptor;
	ia32_selector_t selector;
	Bit16u raw_selector;
	Bit32u dword1, dword2;


	if (CPL != 0) 
	{
		exception(IA32_GP_EXCEPTION, 0, 0);
	}

	if (i->modC0()) 
	{
		raw_selector = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &raw_selector);
	}

	if ((raw_selector & 0xfffc) == 0) 
	{
		tr.selector.value = raw_selector;
		tr.cache.valid = 0;
		return;
	}

	parse_selector(raw_selector, &selector);

	if (selector.ti) 
	{
		exception(IA32_GP_EXCEPTION, raw_selector & 0xfffc, 0);
		return;
	}

	fetch_raw_descriptor(&selector, &dword1, &dword2, IA32_GP_EXCEPTION);
	parse_descriptor(dword1, dword2, &descriptor);
	if (descriptor.valid==0 || descriptor.segment || (descriptor.type!=IA32_SYS_SEGMENT_AVAIL_286_TSS && descriptor.type!=IA32_SYS_SEGMENT_AVAIL_386_TSS)) 
	{
		exception(IA32_GP_EXCEPTION, raw_selector & 0xfffc, 0);
		return;
	}

	if (descriptor.p==0) 
	{
		exception(IA32_NP_EXCEPTION, raw_selector & 0xfffc, 0);
		return;
	}

	tr.selector = selector;
	tr.cache    = descriptor;
	tr.cache.valid = 1;
	dword2 |= 0x00000200; /* set busy bit */
#ifdef IA32_BIG_ENDIAN
	IA32_WriteHostDWordToLittleEndian(&dword2, dword2);
#endif
	m_vm32->access_address_n(this, gdtr.base + selector.index*8 + 4, 4, 0, IA32_WRITE, &dword2);
}

void IA32_CPU::VERR_Ew(Ia32_Instruction_c *i)
{

	Bit16u raw_selector;
	ia32_descriptor_t descriptor;
	ia32_selector_t selector;
	Bit32u dword1, dword2;


	if (i->modC0()) 
	{
		raw_selector = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &raw_selector);
	}

	if ((raw_selector & 0xfffc) == 0) 
	{
		set_ZF(0);
		return;
	}

	parse_selector(raw_selector, &selector);
	if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) 
	{
		set_ZF(0);
		return;
	}

	parse_descriptor(dword1, dword2, &descriptor);

	if (descriptor.segment==0) 
	{
		set_ZF(0); /* inaccessible */
		return;
	}

	if (descriptor.valid==0) 
	{
		set_ZF(0);
		return;
	}

	if (descriptor.u.segment.executable) 
	{ 
		if (descriptor.u.segment.c_ed && descriptor.u.segment.r_w) 
		{
			set_ZF(1); /* accessible */
			return;
		}

		if (descriptor.u.segment.r_w==0) 
		{
			set_ZF(0); /* inaccessible */
			return;
		}

		if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) 
		{
			set_ZF(0); /* inaccessible */
			return;
		}

		set_ZF(1); /* accessible */
	}
	else 
	{ 
		if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) 
		{
			set_ZF(0); /* not accessible */
			return;
		}
		set_ZF(1); /* accessible */
	}

}

void IA32_CPU::VERW_Ew(Ia32_Instruction_c *i)
{

	Bit16u raw_selector;
	ia32_descriptor_t descriptor;
	ia32_selector_t selector;
	Bit32u dword1, dword2;

	if (i->modC0()) 
	{
		raw_selector = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &raw_selector);
	}

	if ((raw_selector & 0xfffc) == 0) 
	{
		set_ZF(0);
		return;
	}

	parse_selector(raw_selector, &selector);

	if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) 
	{
		set_ZF(0);
		return;
	}

	parse_descriptor(dword1, dword2, &descriptor);
	if (descriptor.segment==0 || descriptor.u.segment.executable) 
	{
		set_ZF(0);
		return;
	}

	if (descriptor.valid==0) 
	{
		set_ZF(0);
		return;
	}

	/* data segment */
	if (descriptor.u.segment.r_w) 
	{ 
		if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) 
		{
			set_ZF(0); /* not accessible */
			return;
		}

		set_ZF(1); /* accessible */
		return;
	}

	set_ZF(0); /* not accessible */
}

void IA32_CPU::SGDT_Ms(Ia32_Instruction_c *i)
{
	if (i->modC0()) 
	{
		UndefinedOpcode(i);
	}


	Bit16u limit_16 =  gdtr.limit;
	Bit32u base_32  =  gdtr.base;
	write_virtual_word(i->seg(), IA32_RMAddr(i), &limit_16);
	write_virtual_dword(i->seg(), IA32_RMAddr(i)+2, &base_32);
}

void IA32_CPU::SIDT_Ms(Ia32_Instruction_c *i)
{

	if (i->modC0()) 
	{
		UndefinedOpcode(i);
	}

	Bit16u limit_16 =  idtr.limit;
	Bit32u base_32  =  idtr.base;

	write_virtual_word(i->seg(), IA32_RMAddr(i), &limit_16);
	write_virtual_dword(i->seg(), IA32_RMAddr(i)+2, &base_32);
}

void IA32_CPU::LGDT_Ms(Ia32_Instruction_c *i)
{
	invalidate_prefetch_q();

	if (CPL!=0) 
	{
		exception(IA32_GP_EXCEPTION, 0, 0);
	}

	if (i->modC0()) 
	{
		UndefinedOpcode(i);
	}

	if (i->os32L()) 
	{
		Bit16u limit_16;
		Bit32u base0_31;

		read_virtual_word(i->seg(), IA32_RMAddr(i), &limit_16);
		read_virtual_dword(i->seg(), IA32_RMAddr(i) + 2, &base0_31);

		gdtr.limit = limit_16;
		gdtr.base = base0_31;
	}
	else
	{
		Bit16u limit_16, base0_15;
		Bit8u base16_23;

		read_virtual_word(i->seg(), IA32_RMAddr(i), &limit_16);
		read_virtual_word(i->seg(), IA32_RMAddr(i) + 2, &base0_15);
		read_virtual_byte(i->seg(), IA32_RMAddr(i) + 4, &base16_23);

		gdtr.limit = limit_16;
		gdtr.base = (base16_23 << 16) | base0_15;
	}

}

void IA32_CPU::LIDT_Ms(Ia32_Instruction_c *i)
{
	Bit16u limit_16;
	Bit32u base_32;
	invalidate_prefetch_q();
	if (CPL!=0) 
	{
		exception(IA32_GP_EXCEPTION, 0, 0);
	}
	if (i->modC0()) 
	{
		UndefinedOpcode(i);
	}
	if (i->os32L()) 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &limit_16);
		read_virtual_dword(i->seg(), IA32_RMAddr(i) + 2, &base_32);
		idtr.limit = limit_16;
		idtr.base = base_32;
	}
	else
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &limit_16);
		read_virtual_dword(i->seg(), IA32_RMAddr(i) + 2, &base_32);
		idtr.limit = limit_16;
		idtr.base = base_32 & 0x00ffffff; /* ignore upper 8 bits */
	}
}
